package com.cmhk.zmail

import com.sun.mail.imap.IMAPFolder
import org.grails.web.util.WebUtils
import org.joda.time.DateTime
import org.joda.time.Days
import org.springframework.beans.factory.InitializingBean

import javax.mail.*
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeMessage
import javax.mail.internet.MimeUtility
import javax.servlet.http.HttpSession

class MailService implements InitializingBean {

    def grailsApplication
    def props
    def storeType
//    def request = WebUtils.retrieveGrailsWebRequest().currentRequest
//    HttpSession session = request.session

    @Override
    void afterPropertiesSet() throws Exception {
        props = new Properties()
        def coreMailConfig = grailsApplication.config.coremail
        storeType = coreMailConfig.storeType
        props.put "mail.store.protocol", storeType
        props.put "mail.imap.host", coreMailConfig.host
        props.put "mail.imap.port", coreMailConfig.port
    }

    public HttpSession getSession() {
        WebUtils.retrieveGrailsWebRequest().currentRequest.session
    }


    public Store getStore() {
        def session = getSession()
        Store store = session['MAIL_STORE']
        if (store && store.isConnected()) {
            return store
        } else {
            def zMailUser = session['Z_MAIL_USER']
            store = Session.getDefaultInstance(props).getStore()
            store.connect(zMailUser.username, zMailUser.password)
            if (store.isConnected())
                return store
            else
                throw new Exception("auth error")
        }
    }

    public Boolean authenticate(String username, String password) throws AuthenticationFailedException, MessagingException {
        def mailSession = Session.getDefaultInstance props
        def store = mailSession.getStore()
        store.connect(username, password)
        def auth = store.isConnected()
        if (auth)
            getSession()['MAIL_STORE'] = store

        return auth
    }

//    public List listFolder(String username, String password) {
//        def session = Session.getDefaultInstance props
//        def store = session.getStore()
//        store.connect(username, password)
//        def folderList = grailsApplication.config.coremail.folders.collect { k, v ->
//            def folder = store.getFolder(k)
//            [folderKey: k, name: v.name, icon: v.icon, badgeStyle: v.badgeStyle, messageCount: folder.getMessageCount()]
//        }
//        store.close()
//        return folderList
//    }

    public List listFolder() {
        def store = getStore()

        def folderList = grailsApplication.config.coremail.folders.collect { k, v ->
            def folder = store.getFolder(k)
            [folderKey: k, name: v.name, icon: v.icon, badgeStyle: v.badgeStyle, messageCount: folder.getMessageCount()]
        }

        return folderList
    }


    public Map getMailData(String folderName, Integer startNum, Integer endNum) {
        Store store = getStore()
        def folder = store.getFolder(folderName)
        folder.open(Folder.READ_ONLY)
        def messageCount = folder.getMessageCount()
        def mailMessageList = folder.getMessages(startNum, endNum).reverse().collect {
            MimeMessage mimeMessage = (MimeMessage) it;
            String uid = Long.toString(folder.getUID(mimeMessage));
            [uid   : uid, subject: mimeMessage.subject, from: "${it.sender.getPersonal() ?: it.sender.getAddress()}",
             readed: it.getFlags().contains(Flags.Flag.SEEN), sendDate: handleSendDate(it.getSentDate())]
        }
        folder.close(true)
        [folderName: folderName, messageCount: messageCount, messageList: mailMessageList, startNum: startNum, endNum: endNum]
    }

    public Map getMailData(String folderName) {
        Store store = getStore()
        def folder = store.getFolder(folderName)
        folder.open(Folder.READ_ONLY)
        def messageCount = folder.getMessageCount()
        def startNum = (messageCount - 9) > 0 ? (messageCount - 9) : 1
        def mailMessageList = folder.getMessages(startNum, messageCount).reverse().collect {
            MimeMessage mimeMessage = (MimeMessage) it;
            String uid = Long.toString(folder.getUID(mimeMessage));
            [uid   : uid, subject: it.subject, from: "${it.sender.getPersonal() ?: it.sender.getAddress()}",
             readed: it.getFlags().contains(Flags.Flag.SEEN), sendDate: handleSendDate(it.getSentDate())]
        }
        folder.close(true)
        [folderName: folderName, messageCount: messageCount, messageList: mailMessageList, pullDownStartNum: messageCount + 1, pullUpStartNum: (startNum - 10) > 0 ? (startNum - 10) : 1]
    }


    public Integer getMailCountByFolder(String folderName) {
        Store store = getStore()
        def folder = store.getFolder(folderName)
        folder.open(Folder.READ_ONLY)
        def messageCount = folder.getMessageCount()
        folder.close(true)
        return messageCount
    }


    public String handleSendDate(Date sendDate) {
        def sendDateString
        def now = new DateTime().withTimeAtStartOfDay()
        def sendDateTime = new DateTime(sendDate.getTime())
        def sendDateStartTime = sendDateTime.withTimeAtStartOfDay()

        def days = Days.daysBetween(sendDateStartTime, now).getDays()
        switch (days) {
            case 0:
                sendDateString = sendDateTime.toString("HH:mm")
                break;
            case 1:
                sendDateString = '昨天'
                break;
            case 2..7:
                sendDateString = sendDateTime.toString("EE")
                break;
            default:
                sendDateString = sendDateTime.toString("MM-dd")
                break;
        }

        return sendDateString
    }

    public Map getMailMessageByUid(String folderName, Long uid) {
        def mailContent = [:]
        def store = getStore()
        IMAPFolder folder = store.getFolder(folderName)
        folder.open(Folder.READ_WRITE)
        def msg = folder.getMessageByUID(uid)
        Address[] froms = msg.getFrom();
        if (froms != null) {
            //System.out.println("发件人信息:" + froms[0]);
            InternetAddress addr = (InternetAddress) froms[0];
            mailContent.put("from", [mail: addr.getAddress(), name: addr.getPersonal()])


        }
        mailContent.put("subject", msg.getSubject())


        Object o = msg.getContent();
        if (o instanceof Multipart) {
            Multipart multipart = (Multipart) o;
            reMultipart(multipart, mailContent);
        } else if (o instanceof Part) {
            Part part = (Part) o;
            rePart(part, mailContent);
        } else {
            if (msg.getContentType().startsWith("text/plain")) {
                mailContent.put("text", msg.getContent())
            } else if (msg.getContentType().startsWith("text/html")) {
                mailContent.put("html", msg.getContent())
            } else {
            }

        }
        folder.close(true)
        return mailContent
    }

    private void reMultipart(Multipart multipart, Map mailContent) throws Exception {
        multipart.getCount().times { i ->
            Part part = multipart.getBodyPart(i);
            if (part.getContent() instanceof Multipart) {
                Multipart p = (Multipart) part.getContent();// 转成小包裹
                reMultipart(p, mailContent);
            } else {
                rePart(part, mailContent);
            }
        }
    }

    private void rePart(Part part, Map mailContent) throws MessagingException,
            UnsupportedEncodingException, IOException, FileNotFoundException {
        if (part.getDisposition() != null) {
            String fileName = part.getFileName()

            String attachmentName = fileName?MimeUtility.decodeText(fileName):'';
            def attachments = mailContent.attachments ?: []
            InputStream is = part.getInputStream();

            attachments << [name: attachmentName, contentType: part.getContentType(), data: is.getBytes()]
            mailContent.put("attachments", attachments)
        } else {
            if (part.getContentType().startsWith("text/plain")) {
                mailContent.put("text", part.getContent())
            } else if (part.getContentType().startsWith("text/html")) {
                mailContent.put("html", part.getContent())
            } else {
            }
        }
    }

}
